#include "corp_module.h"

#include "WLcJSON.h"
#include "wl_http_client.h"
#include "protocol_client.h"
#include "repo.h"
#include "weilapb.h"
#include "weilapb_defines.h"
#include "wlsdk_define.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
    CORP_HTTP_SYNC_MY_ORG       = 0,
    CORP_HTTP_SYNC_ADDRESS_LIST = 1,
    CORP_HTTP_SYNC_JOIN_GROUPS  = 2,
} wl_corp_http_type;

typedef struct {
    wlsdk_message_callback callback;
    wl_bool                sync_org;    // 同步组织 wl_true 需要同步 wl_false 不需要同步
    WL_TIMER               sync_timer;  // 同步定时器
} wl_corp_global;

static wl_corp_global s_corp_global;

static wl_int32 corp_protocol_client_listen_callback(PBWeilaMsg* message, void* context);
static wl_int32 corp_message_callback(wl_int32 msgid, void* data, wl_uint32 datalen);
static void     corp_start_sync_timer(void);
static void     corp_stop_sync_timer(void);
static void     corp_sync_my_org(void);
static void     corp_sync_address_list(void);
static void     corp_sync_join_groups(void);

static void corp_sdk_message_callback(wl_uint32 msgid, wl_int32 resultcode, void* msgdata, wl_uint32 datalen) {
    if (s_corp_global.callback) {
        WLLOGD("msgid %d", msgid);
        s_corp_global.callback(msgid, resultcode, msgdata, datalen);
    }
}

static void corp_sync_check(void) {
    // 已登录
    if (WLSDK_LOGIN_ONLINE == repo_get_login_state()) {
        // 用户是企业用户
        repo_user userinfo;
        repo_get_selfinfo(&userinfo);
        // 企业设备
        if ((0x10 & userinfo.type) == 0x10) {
            // 需要同步org
            if (s_corp_global.sync_org) {
                corp_sync_my_org();
                return;
            } else {
                // 通讯录版本检查
                repo_corp corp;
                wl_uint32 address_version = repo_get_corp_address_version();
                wl_uint32 group_version   = repo_get_corp_group_version();
                repo_get_corp(&corp);
                // 同步企业通讯录
                if (corp.address_version > address_version) {
                    wl_core_send_message(WL_MODULE_CORP, CORP_MSG_SYNC_ADDRESS_LIST, wl_null, 0);
                }
                // 同步群组
                if (corp.group_version > group_version) {
                    wl_core_send_message(WL_MODULE_CORP, CORP_MSG_SYNC_JOIN_GROUPS, wl_null, 0);
                }
                // 同步完成
                if (corp.address_version <= address_version && corp.group_version <= group_version) {
                    protocol_client_set_session_depend(PROTOCOL_CLIENT_SESSION_DEPEND_FRIEND);
                    protocol_client_set_session_depend(PROTOCOL_CLIENT_SESSION_DEPEND_GROUP);
                    // 停止同步定时器
                    corp_stop_sync_timer();
                }
            }
        } else {
            // 停止同步定时器
            corp_stop_sync_timer();
        }
    }
}

static void corp_sync_timer_callback(WL_TIMER timer, void* context) {
    corp_sync_check();
}

static void corp_start_sync_timer(void) {
    corp_stop_sync_timer();
    s_corp_global.sync_timer = wl_timer_start(
        HTTP_CLIENT_REQUEST_TIMEOUT_30 * 1000, REPETITIVE, corp_sync_timer_callback, wl_null, WL_TASK_APP, "corp_sync");
    if (WL_INVALID_TIMER == s_corp_global.sync_timer) {
        WLLOGW("wl_timer_start fail");
        return;
    }
}

static void corp_stop_sync_timer(void) {
    if (WL_INVALID_TIMER != s_corp_global.sync_timer) {
        wl_timer_stop(s_corp_global.sync_timer);
        s_corp_global.sync_timer = WL_INVALID_TIMER;
    }
}

static void corp_process_address_list(WLcJSON* address_obj) {
    if (address_obj) {
        wl_uint32 version = 0;
        WLcJSON*  value_obj;
        // 设置通讯录版本号
        value_obj = WLcJSON_GetObjectItem(address_obj, "version");
        if (wl_null != value_obj) {
            version = (wl_uint32)WLcJSON_GetNumberValue(value_obj);
        }
        // 通讯录成员信息
        value_obj = WLcJSON_GetObjectItem(address_obj, "members");
        if (wl_null != value_obj) {
            wl_int32     member_index = 0;
            wl_int32     member_count = WLcJSON_GetArraySize(value_obj);
            repo_friend* friendinfos  = (repo_friend*)wl_malloc(sizeof(repo_friend) * member_count);
            if (wl_null == friendinfos) {
                WLLOGW("malloc fail");
                return;
            }
            memset(friendinfos, 0, sizeof(repo_friend) * member_count);
            for (member_index = 0; member_index < member_count; member_index++) {
                WLcJSON* obj        = wl_null;
                WLcJSON* member_obj = WLcJSON_GetArrayItem(value_obj, member_index);
                obj                 = WLcJSON_GetObjectItem(member_obj, "id");
                if (obj) {
                    friendinfos[member_index].friend.userid = (wl_uint32)WLcJSON_GetNumberValue(obj);
                }
                obj = WLcJSON_GetObjectItem(member_obj, "num");
                if (obj) {
                    strncpy(friendinfos[member_index].friend.number,
                            WLcJSON_GetStringValue(obj),
                            sizeof(friendinfos[member_index].friend.number));
                    friendinfos[member_index].friend.number[sizeof(friendinfos[member_index].friend.number) - 1] = '\0';
                }
                obj = WLcJSON_GetObjectItem(member_obj, "name");
                if (obj) {
                    strncpy(friendinfos[member_index].friend.nick,
                            WLcJSON_GetStringValue(obj),
                            sizeof(friendinfos[member_index].friend.nick));
                    friendinfos[member_index].friend.nick[sizeof(friendinfos[member_index].friend.nick) - 1] = '\0';
                }
                friendinfos[member_index].type = REPO_FRIEND_CORP_MEMBER;
            }
            // 通讯录部门成员Id
            value_obj = WLcJSON_GetObjectItem(address_obj, "dept_memberids");
            if (wl_null != value_obj) {
                wl_int32 dppt_member_index = 0;
                wl_int32 dept_member_count = WLcJSON_GetArraySize(value_obj);
                for (dppt_member_index = 0; dppt_member_index < dept_member_count; dppt_member_index++) {
                    WLcJSON*  memberid_obj = WLcJSON_GetArrayItem(value_obj, dppt_member_index);
                    wl_uint32 memberid     = (wl_uint32)WLcJSON_GetNumberValue(memberid_obj);
                    for (member_index = 0; member_index < member_count; member_index++) {
                        // 部门成员
                        if (friendinfos[member_index].friend.userid == memberid) {
                            friendinfos[member_index].type = REPO_FRIEND_CORP_DEPT;
                            break;
                        }
                    }
                }
            }
            repo_set_corp_address_list(version, friendinfos, member_count);
            wl_free(friendinfos);
        }
    }
}

static void corp_http_client_callback(wl_uint32 resultcode,
                                      wl_char*  content,
                                      wl_uint32 content_len,
                                      wl_uint32 content_type,
                                      void*     context) {
    WLLOGD("result %d context:%d", resultcode, (wl_int32)context);
    if (WLSDK_RESULT_SUCCESS == resultcode) {
        if (content && HTTP_CLIENT_CONTENT_JSON == content_type) {
            WLcJSON* result_obj = WLcJSON_Parse(content);
            if (result_obj) {
                WLcJSON* errcode_obj = WLcJSON_GetObjectItem(result_obj, "errcode");
                if (errcode_obj) {
                    resultcode = (wl_int32)WLcJSON_GetNumberValue(errcode_obj);
                    WLLOGD("result %d", resultcode);
                    if (WLSDK_RESULT_SUCCESS == resultcode) {
                        // SOS成功响应
                        if (CORP_HTTP_SYNC_MY_ORG == (wl_int32)context) {
                            WLcJSON* data_obj = WLcJSON_GetObjectItem(result_obj, "data");
                            WLLOGW("content is %s", content);
                            if (data_obj) {
                                WLcJSON* corp_obj = WLcJSON_GetObjectItem(data_obj, "corp");
                                if (corp_obj) {
                                    repo_corp corp;
                                    WLcJSON*  value_obj;
                                    memset(&corp, 0, sizeof(repo_corp));
                                    value_obj = WLcJSON_GetObjectItem(corp_obj, "num");
                                    if (wl_null != value_obj) {
                                        corp.number = (wl_uint64)WLcJSON_GetNumberValue(value_obj);
                                    }
                                    value_obj = WLcJSON_GetObjectItem(corp_obj, "name");
                                    if (wl_null != value_obj) {
                                        strncpy(corp.name, WLcJSON_GetStringValue(value_obj), sizeof(corp.name));
                                        corp.name[sizeof(corp.name) - 1] = '\0';
                                    }
                                    value_obj = WLcJSON_GetObjectItem(corp_obj, "group_ver");
                                    if (wl_null != value_obj) {
                                        corp.group_version = (wl_uint32)WLcJSON_GetNumberValue(value_obj);
                                    }
                                    value_obj = WLcJSON_GetObjectItem(corp_obj, "address_ver");
                                    if (wl_null != value_obj) {
                                        corp.address_version = (wl_uint32)WLcJSON_GetNumberValue(value_obj);
                                    }
                                    value_obj = WLcJSON_GetObjectItem(corp_obj, "tts");
                                    if (wl_null != value_obj) {
                                        corp.tts = (wl_uint32)WLcJSON_GetNumberValue(value_obj);
                                    }
                                    value_obj = WLcJSON_GetObjectItem(corp_obj, "loc_share");
                                    if (wl_null != value_obj) {
                                        corp.loc_share = (wl_uint32)WLcJSON_GetNumberValue(value_obj);
                                    }
                                    value_obj = WLcJSON_GetObjectItem(corp_obj, "track");
                                    if (wl_null != value_obj) {
                                        corp.track = (wl_uint32)WLcJSON_GetNumberValue(value_obj);
                                    }
                                    value_obj = WLcJSON_GetObjectItem(corp_obj, "state");
                                    if (wl_null != value_obj) {
                                        corp.state = (wl_uint32)WLcJSON_GetNumberValue(value_obj);
                                    }
                                    repo_set_corp(&corp);
                                    s_corp_global.sync_org = wl_false;
                                    // 同步检查
                                    corp_sync_check();
                                }
                            }
                        } else if (CORP_HTTP_SYNC_ADDRESS_LIST == (wl_int32)context) {
                            WLcJSON* data_obj = WLcJSON_GetObjectItem(result_obj, "data");
                            WLLOGW("content is %s", content);
                            if (data_obj) {
                                WLcJSON* address_obj = WLcJSON_GetObjectItem(data_obj, "address_list");
                                corp_process_address_list(address_obj);
                            }
                            protocol_client_set_session_depend(PROTOCOL_CLIENT_SESSION_DEPEND_FRIEND);
                        } else if (CORP_HTTP_SYNC_JOIN_GROUPS == (wl_int32)context) {
                            WLcJSON* data_obj = WLcJSON_GetObjectItem(result_obj, "data");
                            WLLOGW("content is %s", content);
                            if (data_obj) {
                                wl_uint32 version = 0;
                                WLcJSON*  value_obj;
                                WLcJSON*  groups_obj = WLcJSON_GetObjectItem(data_obj, "groups");
                                // 设置通讯录版本号
                                value_obj = WLcJSON_GetObjectItem(data_obj, "version");
                                if (wl_null != value_obj) {
                                    version = (wl_uint32)WLcJSON_GetNumberValue(value_obj);
                                }
                                if (groups_obj) {
                                    wl_int32    group_index = 0;
                                    wl_int32    group_count = WLcJSON_GetArraySize(groups_obj);
                                    repo_group* groupinfos  = (repo_group*)wl_malloc(sizeof(repo_group) * group_count);
                                    if (wl_null == groupinfos) {
                                        WLLOGW("malloc fail");
                                        return;
                                    }
                                    memset(groupinfos, 0, sizeof(repo_group) * group_count);
                                    for (group_index = 0; group_index < group_count; group_index++) {
                                        WLcJSON* obj       = wl_null;
                                        WLcJSON* group_obj = WLcJSON_GetArrayItem(groups_obj, group_index);
                                        obj                = WLcJSON_GetObjectItem(group_obj, "id");
                                        if (obj) {
                                            groupinfos[group_index].group.groupid =
                                                (wl_uint64)WLcJSON_GetNumberValue(obj);
                                        }
                                        obj = WLcJSON_GetObjectItem(group_obj, "name");
                                        if (obj) {
                                            strncpy(groupinfos[group_index].group.group_name,
                                                    WLcJSON_GetStringValue(obj),
                                                    sizeof(groupinfos[group_index].group.group_name));
                                            groupinfos[group_index]
                                                .group
                                                .group_name[sizeof(groupinfos[group_index].group.group_name) - 1] =
                                                '\0';
                                        }
                                        obj = WLcJSON_GetObjectItem(group_obj, "type");
                                        if (obj) {
                                            groupinfos[group_index].group.group_type =
                                                (wl_uint16)WLcJSON_GetNumberValue(obj);
                                        }
                                        obj = WLcJSON_GetObjectItem(group_obj, "burst_mode");
                                        if (obj) {
                                            groupinfos[group_index].group.bursttype =
                                                (wl_uint16)WLcJSON_GetNumberValue(obj);
                                        }
                                        obj = WLcJSON_GetObjectItem(group_obj, "shutup");
                                        if (obj) {
                                            groupinfos[group_index].group.shutupstatus =
                                                (wl_uint16)WLcJSON_GetNumberValue(obj);
                                        }
                                    }
                                    repo_set_corp_groups(version, groupinfos, group_count);
                                    wl_free(groupinfos);
                                }
                            }
                            protocol_client_set_session_depend(PROTOCOL_CLIENT_SESSION_DEPEND_GROUP);
                        }
                    }
                } else {
                    resultcode = WLSDK_RESULT_DATA_INVALID;
                }
                WLcJSON_Delete(result_obj);
            } else {
                resultcode = WLSDK_RESULT_DATA_INVALID;
            }
            WLLOGD("resultcode:%d context:%d", resultcode, (wl_int32)context);
        }
    }
}

wl_int32 corp_module_init(wlsdk_message_callback callback) {
    wl_int32  ret = 0;
    wl_module module;

    WLLOGI("corp_module_init");
    memset(&module, 0, sizeof(wl_module));
    module.moduleid = WL_MODULE_CORP;
    module.taskid   = WL_TASK_APP;
    module.callback = corp_message_callback;
    ret             = wl_core_register_module(&module);
    if (0 != ret) {
        WLLOGW("wl_core_register_module corp fail");
        return ret;
    }
    s_corp_global.callback = callback;
    protocol_client_add_listen(
        WL_SYSTEM_NOTIFICATION_MSG, WEILA_MSG_IND, corp_protocol_client_listen_callback, wl_null);
    return ret;
}

wl_int32 corp_module_end(void) {
    WLLOGI("corp_module_end");
    wl_core_unregister_module(WL_MODULE_LOCATION);
    s_corp_global.callback = wl_null;
    return 0;
}

static wl_char* corp_create_sign_content(void) {
    WLcJSON* root_obj = WLcJSON_CreateObject();
    wl_char* content  = wl_null;
    if (wl_null == root_obj) {
        WLLOGW("WLcJSON_CreateObject fail");
        return wl_null;
    }
    repo_build_http_sign(root_obj);
    content = WLcJSON_PrintUnformatted(root_obj);

    WLcJSON_Delete(root_obj);
    return content;
}

static void corp_http_request(wl_int32 method_type, wl_char* content) {
    wl_char     server_url[MAX_URL_LEN];
    wl_char     token[MAX_TOKEN_LEN + 1];
    wl_char*    method = "report-corp";
    repo_server web_server;
    repo_get_token(token);
    repo_get_web_server(&web_server);
    switch (method_type) {
        case CORP_HTTP_SYNC_ADDRESS_LIST:
            method = "get-address-list";
            break;
        case CORP_HTTP_SYNC_JOIN_GROUPS:
            method = "group-get-join-groups";
            break;
        case CORP_HTTP_SYNC_MY_ORG:
            method = "org-my-org";
            break;
        default:
            break;
    }
    sprintf(
        server_url, "http://%s:%d/v1/corp/device/%s?access-token=%s", web_server.host, web_server.port, method, token);
    WLLOGD("server_url %s", server_url);
    if (0
        != wl_http_client_post(server_url,
                            HTTP_CLIENT_REQUEST_TIMEOUT_15,
                            content,
                            strlen(content),
                            HTTP_CLIENT_CONTENT_JSON,
                            corp_http_client_callback,
                            (void*)method_type)) {
        WLLOGW("wl_http_client_post %s error", server_url);
    }
}

static void corp_sync_my_org(void) {
    wl_char* content = corp_create_sign_content();
    if (content) {
        corp_http_request(CORP_HTTP_SYNC_MY_ORG, content);
        WLcJSON_free(content);
    }
}

static void corp_sync_address_list(void) {
    wl_char* content = corp_create_sign_content();
    if (content) {
        corp_http_request(CORP_HTTP_SYNC_ADDRESS_LIST, content);
        WLcJSON_free(content);
    }
}

static void corp_sync_join_groups(void) {
    wl_char* content = corp_create_sign_content();
    if (content) {
        corp_http_request(CORP_HTTP_SYNC_JOIN_GROUPS, content);
        WLcJSON_free(content);
    }
}

static wl_int32 corp_message_callback(wl_int32 msgid, void* data, wl_uint32 datalen) {
    WLLOGD("msgid %d", msgid);
    switch (msgid) {
        case CORP_MSG_SYNC_START:
            s_corp_global.sync_org = wl_true;
            // 启动同步检查定时器
            corp_start_sync_timer();
            corp_sync_check();
            break;
        case CORP_MSG_SYNC_MY_ORG:
            corp_sync_my_org();
            break;
        case CORP_MSG_SYNC_ADDRESS_LIST:
            corp_sync_address_list();
            break;
        case CORP_MSG_SYNC_JOIN_GROUPS:
            corp_sync_join_groups();
            break;
        default:
            WLLOGW("msgid %d not support", msgid);
            break;
    }
    return 0;
}

static void process_corp_system_notify_message(PBWeilaMsg* message, void* context) {
    if (message->contentSize > 0) {
        PBString* pbString = (PBString*)message->pContent;
        WLcJSON*  root_obj = WLcJSON_Parse((wl_char*)pbString->str);
        WLLOGD("pContent %s", pbString->str);
        if (root_obj) {
            WLcJSON* msgtype_obj = WLcJSON_GetObjectItem(root_obj, "msg_type");
            if (msgtype_obj) {
                wl_char msgtype[MAX_NAME_LEN];
                strncpy(msgtype, WLcJSON_GetStringValue(msgtype_obj), sizeof(msgtype));
                msgtype[sizeof(msgtype) - 1] = '\0';
                // 设备群变更
                if (0 == strcmp(msgtype, "corp-device-group-change")) {
                    wl_core_send_message(WL_MODULE_CORP, CORP_MSG_SYNC_JOIN_GROUPS, wl_null, 0);
                    // 启动同步检查定时器
                    corp_start_sync_timer();
                }
                // 设备群成员变更
                else if (0 == strcmp(msgtype, "corp-device-group-member-change")) {
                    wl_core_send_message(WL_MODULE_CORP, CORP_MSG_SYNC_JOIN_GROUPS, wl_null, 0);
                    // 启动同步检查定时器
                    corp_start_sync_timer();
                }
                // 设备通讯录变更
                else if (0 == strcmp(msgtype, "corp-device-address-change")) {
                    wl_core_send_message(WL_MODULE_CORP, CORP_MSG_SYNC_ADDRESS_LIST, wl_null, 0);
                    // 启动同步检查定时器
                    corp_start_sync_timer();
                }
            }
            WLcJSON_Delete(root_obj);
        }
    }
}

static wl_int32 corp_protocol_client_listen_callback(PBWeilaMsg* message, void* context) {
    WLLOGI("message %d", message->message);
    switch (message->message) {
        case WL_SYSTEM_NOTIFICATION_MSG: {
            process_corp_system_notify_message(message, context);
            break;
        }
        default:
            break;
    }
    return 0;
}

#ifdef __cplusplus
}
#endif
